﻿using Yt.Core.IPC.NamedPipe;
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Yt.Core.IPC
{
    /// <summary>
    /// 通信代理类
    /// </summary>
    public class IpcProxy
    {
        private static Dictionary<string, IpcProxy> clientProxyList = new Dictionary<string, IpcProxy>();
        private static Dictionary<string, IpcProxy> serverProxyList = new Dictionary<string, IpcProxy>();
        /// <summary>
        /// 管道连接事件
        /// </summary>
        public ConnectionHandler OnConnection;
        /// <summary>
        /// 管道断开连接事件
        /// </summary>
        public ConnectionHandler OnDisconnect;
        /// <summary>
        /// 管道错误事件
        /// </summary>
        public ErrorHandler OnError;
        private PipeBuilderBase builder { get; set; }
        private bool HasReturn { get; set; }
        private string ReturnResult { get; set; }
        /// <summary>
        /// 代理的管道名称
        /// </summary>
        public string Name => builder?.Name;

        

        /// <summary>
        /// 创建客户端代理
        /// </summary>
        public static IpcProxy CreateClient(string pipeName)
        {
            if (clientProxyList.ContainsKey(pipeName))
            {
                
                return clientProxyList[pipeName];
            }

            IpcProxy ipcProxy = new IpcProxy();
            ipcProxy.builder = PipeClientBuilder.CreateBuilder(pipeName);
            AddHandler(ipcProxy);
            clientProxyList[pipeName] = ipcProxy;

           

            return ipcProxy;
        }
        /// <summary>
        /// 创建服务端代理
        /// </summary>
        public static IpcProxy CreateServer(string pipeName)
        {
            if (serverProxyList.ContainsKey(pipeName))
            {
                
                return serverProxyList[pipeName];
            }
            IpcProxy ipcProxy = new IpcProxy();
            ipcProxy.builder = PipeServerBuilder.CreateBuilder(pipeName);
            AddHandler(ipcProxy);
            serverProxyList[pipeName] = ipcProxy;

         

            return ipcProxy;
        }

        /// <summary>
        /// 连接管道，开始工作,用于服务端
        /// </summary>
        public void Connect()
        {
            builder.Connect();
        }
        /// <summary>
        ///关闭代理
        /// </summary>
        public static void CloseProxy(string pipeName)
        {
            if (clientProxyList.ContainsKey(pipeName))
            {
                clientProxyList[pipeName].Dispose();
            }
            if (serverProxyList.ContainsKey(pipeName))
            {
                serverProxyList[pipeName].Dispose();
            }
        }

        private static void AddHandler(IpcProxy ipcProxy)
        {
            ipcProxy.builder.OnConnection = () => { ipcProxy.OnConnection?.Invoke(); };
            ipcProxy.builder.OnDisconnect = () => { ipcProxy.OnDisconnect?.Invoke(); };
            ipcProxy.builder.OnError = (e) => { ipcProxy.OnError?.Invoke(e); };
        }
        /// <summary>
        /// 远程调用
        /// </summary>
        /// <typeparam name="I">接口类型</typeparam>
        /// <param name="exp">Expression表达式</param>
        public void RemoteInvoke<I>(Expression<Action<I>> exp, Action callBack = null)
        {
            RemoteInvoke<object, I>(exp, callBack);
        }
        /// <summary>
        /// 带返回值的远程调用
        /// </summary>
        /// <typeparam name="R">返回类型</typeparam>
        /// <typeparam name="I">接口类型</typeparam>
        /// <param name="exp">Expression表达式</param>
        /// <returns>返回给定的类型返回值</returns>
        public R RemoteInvoke<R, I>(Expression<Action<I>> exp, Action callBack = null)
        {
            if (exp.Body is MethodCallExpression)
            {
                MethodCallExpression me = (MethodCallExpression)exp.Body;
                MethodInfo methodInfo = me.Method;
                string methodName = methodInfo.Name;
                bool IsVoid = methodInfo.ReturnType == typeof(void);

                List<object> argList = new List<object>();
                int argindex = 1;
                foreach (var a in me.Arguments)
                {
                    Type ttt = null;
                    if (a is ConstantExpression)
                    {
                        var argExp = (ConstantExpression)a;
                        argList.Add(argExp.Value);
                        ttt = argExp.Type;
                    }
                    else if (a is MemberExpression)
                    {
                        var argExp = (MemberExpression)a;
                        argList.Add(GetMemberValue(argExp));
                        ttt = argExp.Type;
                    }
                    else
                    {
                        throw new NotSupportedException("第 " + argindex + " 个参数错误！参数只能为常量或者变量");
                    }
                    argindex++;
                }
                MessageData messageData = new MessageData()
                {
                    TypeName = typeof(I).FullName + "," + typeof(I).Assembly.GetName().Name,
                    MethodName = methodName,
                    Args = argList
                };
                Message message = new Message() { MessageType = MessageType.Request, Data = JsonSerializeHelper.ToJson(messageData) };
                if (!IsVoid)
                {
                    builder.CallBack = (p) =>
                    {
                        ReturnResult = p;
                        HasReturn = true;
                    };
                }
                else
                {
                    message.MessageType = MessageType.NoReplyRequest;
                }
                builder.Send(JsonSerializeHelper.ToJson(message), callBack);
                if (!IsVoid)
                {
                    Task task = new Task(() => { });
                    Task.Run(() =>
                    {
                        while (true)
                        {
                            System.Threading.Thread.Sleep(10);
                             Application.DoEvents();
                            if (HasReturn) break;
                        }
                    }).Wait();
                    return (R)JsonSerializeHelper.ToObject(methodInfo.ReturnType, ReturnResult);
                }
                else
                {
                    return default(R);
                }
            }
            else
            {
                throw new NotSupportedException("不支持的表达式");
            }
        }
        private object GetMemberValue(MemberExpression member)
        {
            var objectMember = Expression.Convert(member, typeof(object));

            var getterLambda = Expression.Lambda<Func<object>>(objectMember);

            var getter = getterLambda.Compile();

            return getter();
        }
        /// <summary>
        /// 关联接口与对象
        /// </summary>
        /// <typeparam name="Interface">接口类型</typeparam>
        /// <param name="service">实现接口的对象</param>
        public void AddService<Interface>(object service)
        {
            builder.AddService<Interface>(service);
        }
       
        /// <summary>
        /// 移除关联对象
        /// </summary>
        /// <typeparam name="Interface">接口类型</typeparam>
        public void RemoveService<Interface>()
        {
            builder.RemoveService<Interface>();
        }
        /// <summary>
        /// 移除关联对象
        /// </summary>
        /// <param name="service">待移除的对象</param>
        public void RemoveService(object service)
        {
            builder.RemoveService(service);
        }
        public void Dispose()
        {
            if (builder != null)
            {
                if (clientProxyList.ContainsKey(builder.Name)) clientProxyList.Remove(builder.Name);
                if (serverProxyList.ContainsKey(builder.Name)) serverProxyList.Remove(builder.Name);
            }
            builder?.Dispose();
        }
        ~IpcProxy()
        {
            Dispose();
        }
    }
}
